package org.infinity;

import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public final class Monitor extends TimerTask {
	private static final Log log = LogFactory.getLog(Monitor.class);

	private List<Long> monitorAverageTime = new ArrayList<Long>();

	private Monitor() {
		// this.setPriority(Thread.MIN_PRIORITY);
	}

	private static Monitor monitor;

	private boolean moniting = true;

	synchronized public static void StartMonitor() {

		if (initial()) {
			// if (monitor == null || monitor.isInterrupted()) {
			// monitor = new Monitor();
			// monitor.start();
			// }
			Timer timer = new Timer();
			Monitor monitor = new Monitor();
			timer.schedule(monitor, Config.getInstance().getFrequency());
		}
	}

	private static boolean initial() {
		log.debug("initial   start");
		File file = Config.getInstance().getDestPath();
		if (!Util.checkPath(file)) {
			return false;
		}
		log.debug("initial   end");
		return true;
	}

	@Override
	public void run() {
		try {
			long dt1;
			long dt2;
			while (isMoniting()) {
				dt1 = System.currentTimeMillis();
				monitor();
				dt2 = System.currentTimeMillis();
				monitorAverageTime.add(dt2 - dt1);
				log.debug("monitorAverageTime:" + getAverageTime() / 1000d);
				try {
					Thread.sleep(Config.getInstance().getFrequency());
				} catch (InterruptedException e) {
					Thread.currentThread().interrupt();
					throw e;
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
			log.error(e);
		}
	}

	synchronized void monitor() {
		log.debug("monitor   start");
		log.debug("iteratorFile   start");
		iteratorFile(Config.getInstance().getDestPath());
		log.debug("iteratorFile   end");
		detectDeletedFile();
		FileMap.getInstance().saveFileMap();
		log.debug("monitor   end");
	}

	/**
	 * Iterator all file of sub director
	 */
	void iteratorFile(File file) {
		// if(!file.isDirectory()){
		// showMessage(getMessage("warn.001"));
		// return;
		// }
		File[] files = file.listFiles();
		if (files == null) {
			return;
		}
		for (File subFile : files) {
			if (subFile.isDirectory()) {
				iteratorFile(subFile);
			} else {
				Long file2 = FileMap.getInstance().get(
						subFile.getAbsoluteFile().toString());
				judgeFile(subFile, file2);
			}
		}
	}

	private Set<String> deleteFileSet = new HashSet<String>();

	/**
     * 
     */
	private void detectDeletedFile() {
		log.debug("detectDeletedFile   start");
		deleteFileSet.clear();
		// detect deleted file
		Set<String> keySet = FileMap.getInstance().keySet();
		for (String fileName : keySet) {
			if (!isExist(fileName)) {
				String lestTime = Util.formatDate(new Date(FileMap
						.getInstance().get(fileName)));
				Util.showMessage("info.002", fileName, lestTime);
				deleteFileSet.add(fileName);
			}
		}
		for (String fileName : deleteFileSet) {
			FileMap.getInstance().remove(fileName);
		}
		log.debug("detectDeletedFile   end");
	}

	/**
	 * is file exist
	 * 
	 * @param fileName
	 * @return
	 */
	private boolean isExist(String fileName) {
		File file = new File(fileName);
		return file.exists();
	}

	synchronized public boolean isMoniting() {
		return moniting;
	}

	synchronized public void setMoniting(boolean moniting) {
		this.moniting = moniting;
	}

	static void judgeFile(File file1, Long file2) {

		// file2 == null || file1.lastModified() != file2.lastModified()
		if (file2 == null) {
			Util.showMessage("info.001", file1.getAbsoluteFile(), Util
					.formatDate(new Date(file1.lastModified())), "new file");
			FileMap.getInstance().put(file1.getAbsolutePath(),
					file1.lastModified());
			return;
		}
		if (file1.lastModified() != file2) {

			Util.showMessage("info.001", file1.getAbsoluteFile(), Util
					.formatDate(new Date(file1.lastModified())), Util
					.formatDate(new Date(file2)));
			FileMap.getInstance().put(file1.getAbsolutePath(),
					file1.lastModified());
			return;
		}
	}

	/**
	 * get average monitor spend time
	 * 
	 * @return
	 */
	public long getAverageTime() {
		long total = 0;
		for (long time : monitorAverageTime) {
			total += time;
		}
		log.debug("total:" + total / 1000d);
		log.debug("times:" + monitorAverageTime.size());
		return total / monitorAverageTime.size();
	}

}
